home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-08-02 | 52.7 KB | 1,869 lines |
- /*
- * Copyright (c) 1992 Carnegie Mellon University
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
- * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
- * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * Carnegie Mellon requests users of this software to return to
- *
- * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
- * School of Computer Science
- * Carnegie Mellon University
- * Pittsburgh PA 15213-3890
- *
- * any improvements or extensions that they make and grant Carnegie Mellon
- * the rights to redistribute these changes.
- *
- /*
- * supfilesrv -- SUP File Server
- *
- * Usage: supfilesrv [-l] [-P] [-N] [-R]
- * -l "live" -- don't fork daemon
- * -P "debug ports" -- use debugging network ports
- * -N "debug network" -- print debugging messages for network i/o
- * -R "RCS mode" -- if file is an rcs file, use co to get contents
- *
- **********************************************************************
- * HISTORY
- * 13-Sep-92 Mary Thompson (mrt) at Carnegie-Mellon University
- * Changed name of sup program in xpatch from /usr/cs/bin/sup to
- * /usr/bin/sup for exported version of sup.
- *
- * 7-July-93 Nate Williams at Montana State University
- * Modified SUP to use gzip based compression when sending files
- * across the network to save BandWidth
- *
- * $Log: supfilesrv.c,v $
- * Revision 1.5 1993/08/04 17:46:21 brezak
- * Changes from nate for gzip'ed sup
- *
- * Revision 1.3 1993/06/05 21:32:17 cgd
- * use daemon() to put supfilesrv into daemon mode...
- *
- * Revision 1.2 1993/05/24 17:57:31 brezak
- * Remove netcrypt.c. Remove unneeded files. Cleanup make.
- *
- * Revision 1.20 92/09/09 22:05:00 mrt
- * Added Brad's change to make sendfile take a va_list.
- * Added support in login to accept an non-encrypted login
- * message if no user or password is being sent. This supports
- * a non-crypting version of sup. Also fixed to skip leading
- * white space from crypts in host files.
- * [92/09/01 mrt]
- *
- * Revision 1.19 92/08/11 12:07:59 mrt
- * Made maxchildren a patchable variable, which can be set by the
- * command line switch -C or else defaults to the MAXCHILDREN
- * defined in sup.h. Added most of Brad's STUMP changes.
- * Increased PGMVERSION to 12 to reflect substantial changes.
- * [92/07/28 mrt]
- *
- * Revision 1.18 90/12/25 15:15:39 ern
- * Yet another rewrite of the logging code. Make up the text we will write
- * and then get in, write it and get out.
- * Also set error on write-to-full-disk if the logging is for recording
- * server is busy.
- * [90/12/25 15:15:15 ern]
- *
- * Revision 1.17 90/05/07 09:31:13 dlc
- * Sigh, some more fixes to the new "crypt" file handling code. First,
- * just because the "crypt" file is in a local file system does not mean
- * it can be trusted. We have to check for hard links to root owned
- * files whose contents could be interpretted as a crypt key. For
- * checking this fact, the new routine stat_info_ok() was added. This
- * routine also makes other sanity checks, such as owner only permission,
- * the file is a regular file, etc. Also, even if the uid/gid of th
- * "crypt" file is not going to be used, still use its contents in order
- * to cause fewer surprises to people supping out of a shared file system
- * such as AFS.
- * [90/05/07 dlc]
- *
- * Revision 1.16 90/04/29 04:21:08 dlc
- * Fixed logic bug in docrypt() which would not get the stat information
- * from the crypt file if the crypt key had already been set from a
- * "host" file.
- * [90/04/29 dlc]
- *
- * Revision 1.15 90/04/18 19:51:27 dlc
- * Added the new routines local_file(), link_nofollow() for use in
- * dectecting whether a file is located in a local file system. These
- * routines probably should have been in another module, but only
- * supfilesrv needs to do the check and none of its other modules seemed
- * appropriate. Note, the implementation should be changed once we have
- * direct kernel support, for example the fstatfs(2) system call, for
- * detecting the type of file system a file resides. Also, I changed
- * the routines which read the crosspatch crypt file or collection crypt
- * file to save the uid and gid from the stat information obtained via
- * the local_file() call (when the file is local) at the same time the
- * crypt key is read. This change disallows non-local files for the
- * crypt key to plug a security hole involving the usage of the uid/gid
- * of the crypt file to define who the the file server should run as. If
- * the saved uid/gid are both valid, then the server will set its uid/gid
- * to these values.
- * [90/04/18 dlc]
- *
- * Revision 1.14 89/08/23 14:56:15 gm0w
- * Changed msgf routines to msg routines.
- * [89/08/23 gm0w]
- *
- * Revision 1.13 89/08/03 19:57:33 mja
- * Remove setaid() call.
- *
- * Revision 1.12 89/08/03 19:49:24 mja
- * Updated to use v*printf() in place of _doprnt().
- * [89/04/19 mja]
- *
- * 11-Sep-88 Glenn Marcy (gm0w) at Carnegie-Mellon University
- * Added code to record release name in logfile.
- *
- * 18-Mar-88 Glenn Marcy (gm0w) at Carnegie-Mellon University
- * Added host=<hostfile> support to releases file. [V7.12]
- *
- * 27-Dec-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
- * Added crosspatch support. Created docrypt() routine for crypt
- * test message.
- *
- * 09-Sep-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
- * Removed common information logging code, the quiet switch, and
- * moved samehost() check to after device/inode check.
- *
- * 28-Jun-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
- * Added code for "release" support. [V5.11]
- *
- * 26-May-87 Doug Philips (dwp) at Carnegie-Mellon University
- * Added code to record final status of client in logfile. [V5.10]
- *
- * 22-May-87 Chriss Stephens (chriss) at Carnegie Mellon University
- * Mergered divergent CS and ECE versions. [V5.9a]
- *
- * 20-May-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
- * Removed support for version 3 of SUP protocol. Added changes
- * to make lint happy. Added calls to new logging routines. [V5.9]
- *
- * 31-Mar-87 Dan Nydick (dan) at Carnegie-Mellon University
- * Fixed so no password check is done when crypts are used.
- *
- * 25-Nov-86 Rudy Nedved (ern) at Carnegie-Mellon University
- * Set F_APPEND fcntl in logging to increase the chance
- * that the log entry from this incarnation of the file
- * server will not be lost by another incarnation. [V5.8]
- *
- * 20-Oct-86 Dan Nydick (dan) at Carnegie-Mellon University
- * Changed not to call okmumbles when not compiled with CMUCS.
- *
- * 04-Aug-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
- * Added code to increment scmdebug as more -N flags are
- * added. [V5.7]
- *
- * 25-May-86 Jonathan J. Chew (jjc) at Carnegie-Mellon University
- * Renamed local variable in main program from "sigmask" to
- * "signalmask" to avoid name conflict with 4.3BSD identifier.
- * Conditionally compile in calls to CMU routines, "setaid" and
- * "logaccess". [V5.6]
- *
- * 21-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
- * Changed supfilesrv to use the crypt file owner and group for
- * access purposes, rather than the directory containing the crypt
- * file. [V5.5]
- *
- * 07-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
- * Added code to keep logfiles in repository collection directory.
- * Added code for locking collections. [V5.4]
- *
- * 05-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
- * Added code to support new FSETUPBUSY return. Now accepts all
- * connections and tells any clients after the 8th that the
- * fileserver is busy. New clients will retry again later. [V5.3]
- *
- * 29-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
- * Major rewrite for protocol version 4. [V4.2]
- *
- * 12-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
- * Fixed close of crypt file to use file pointer as argument
- * instead of string pointer.
- *
- * 24-Nov-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
- * Allow "!hostname" lines and comments in collection "host" file.
- *
- * 13-Nov-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
- * Don't use access() on symbolic links since they may not point to
- * an existing file.
- *
- * 22-Oct-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
- * Added code to restrict file server availability to when it has
- * less than or equal to eight children.
- *
- * 22-Sep-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
- * Merged 4.1 and 4.2 versions together.
- *
- * 04-Jun-85 Steven Shafer (sas) at Carnegie-Mellon University
- * Created for 4.2 BSD.
- *
- **********************************************************************
- */
-
- #include <libc.h>
- #ifdef AFS
- #include <afs/param.h>
- #undef MAXNAMLEN
- #endif
- #include <sys/param.h>
- #include <c.h>
- #include <signal.h>
- #include <errno.h>
- #include <setjmp.h>
- #include <pwd.h>
- #include <grp.h>
- #if __STDC__
- #include <stdarg.h>
- #else
- #include <varargs.h>
- #endif
- #include <sys/time.h>
- #include <sys/resource.h>
- #include <sys/wait.h>
- #include <sys/stat.h>
- #include <sys/file.h>
- #include <sys/dir.h>
- #if MACH
- #include <sys/ioctl.h>
- #endif
- #if CMUCS
- #include <acc.h>
- #include <sys/ttyloc.h>
- #include <access.h>
- #include <sys/viceioctl.h>
- #else CMUCS
- #define ACCESS_CODE_OK 0
- #define ACCESS_CODE_BADPASSWORD (-2)
- #endif CMUCS
- #include "sup.h"
- #define MSGFILE
- #include "supmsg.h"
-
- #ifdef lint
- /*VARARGS1*//*ARGSUSED*/
- static void quit(status) {};
- #endif /* lint */
-
- #if __STDC__
- void goaway (char *,...);
- #endif
-
- extern int errno;
- long time ();
- uid_t getuid ();
-
- int maxchildren;
-
- /*
- * These are used to save the stat information from the crosspatch crypt
- * file or collection crypt file at the time it is opened for the crypt
- * key and it is verified to be a local file.
- */
- int runas_uid = -1;
- int runas_gid = -1;
-
- #define PGMVERSION 13
-
- /*************************
- *** M A C R O S ***
- *************************/
-
- #define HASHBITS 8
- #define HASHSIZE (1<<HASHBITS)
- #define HASHMASK (HASHSIZE-1)
- #define HASHFUNC(x,y) ((x)&HASHMASK)
-
- /*******************************************
- *** D A T A S T R U C T U R E S ***
- *******************************************/
-
- struct hashstruct { /* hash table for number lists */
- int Hnum1; /* numeric keys */
- int Hnum2;
- char *Hname; /* string value */
- TREE *Htree; /* TREE value */
- struct hashstruct *Hnext;
- };
- typedef struct hashstruct HASH;
-
- /*********************************************
- *** G L O B A L V A R I A B L E S ***
- *********************************************/
-
- char program[] = "supfilesrv"; /* program name for SCM messages */
- int progpid = -1; /* and process id */
-
- jmp_buf sjbuf; /* jump location for network errors */
- TREELIST *listTL; /* list of trees to upgrade */
-
- int live; /* -l flag */
- int dbgportsq; /* -P flag */
- extern int scmdebug; /* -N flag */
- extern int netfile;
- #ifdef RCS
- int candorcs; /* -R flag */
- int dorcs = FALSE;
- #endif
-
- char *clienthost; /* host name of client */
- int nchildren; /* number of children that exist */
- char *prefix; /* collection pathname prefix */
- char *release; /* collection release name */
- char *cryptkey; /* encryption key if non-null */
- #ifdef CVS
- char *cvs_root; /* RCS root */
- #endif
- char *rcs_branch; /* RCS branch name */
- int lockfd; /* descriptor of lock file */
-
- /* global variables for scan functions */
- int trace = FALSE; /* directory scan trace */
- int cancompress = FALSE; /* Can we compress files */
- int docompress = FALSE; /* Do we compress files */
-
- HASH *uidH[HASHSIZE]; /* for uid and gid lookup */
- HASH *gidH[HASHSIZE];
- HASH *inodeH[HASHSIZE]; /* for inode lookup for linked file check */
-
- char *fmttime (); /* time format routine */
-
- /*************************************
- *** M A I N R O U T I N E ***
- *************************************/
-
- main (argc,argv)
- int argc;
- char **argv;
- {
- #ifdef _ABI_SOURCE
- register int x,pid;
- sigset_t signalmask, oldsignalmask;
- struct sigaction chldvec,ignvec,oldvec;
- #else
- register int x,pid,signalmask;
- struct sigvec chldvec,ignvec,oldvec;
- #endif
- int chldsig ();
- long tloc;
-
- /* initialize global variables */
- pgmversion = PGMVERSION; /* export version number */
- server = TRUE; /* export that we're not a server */
- collname = NULL; /* no current collection yet */
- maxchildren = MAXCHILDREN; /* defined in sup.h */
-
- init (argc,argv); /* process arguments */
-
- #ifdef HAS_DAEMON
- if (!live) /* if not debugging, turn into daemon */
- daemon(0, 0);
- #endif
-
- logopen ("supfile");
- tloc = time ((long *)NULL);
- loginfo ("SUP File Server Version %d.%d (%s) starting at %s",
- PROTOVERSION,PGMVERSION,scmversion,fmttime (tloc));
- if (live) {
- x = service ();
- if (x != SCMOK)
- logquit (1,"Can't connect to network");
- answer ();
- (void) serviceend ();
- exit (0);
- }
- #ifdef _ABI_SOURCE
- ignvec.sa_handler = SIG_IGN;
- sigemptyset (&(ignvec.sa_mask));
- ignvec.sa_flags = 0;
- (void) sigaction (SIGHUP,&ignvec,&oldvec);
- (void) sigaction (SIGINT,&ignvec,&oldvec);
- (void) sigaction (SIGPIPE,&ignvec,&oldvec);
- chldvec.sa_handler = chldsig;
- sigemptyset (&(chldvec.sa_mask));
- chldvec.sa_flags = 0;
- (void) sigaction (SIGCHLD,&chldvec,&oldvec);
- #else
- ignvec.sv_handler = SIG_IGN;
- ignvec.sv_onstack = 0;
- ignvec.sv_mask = 0;
- (void) sigvec (SIGHUP,&ignvec,&oldvec);
- (void) sigvec (SIGINT,&ignvec,&oldvec);
- (void) sigvec (SIGPIPE,&ignvec,&oldvec);
- chldvec.sv_handler = chldsig;
- chldvec.sv_mask = 0;
- chldvec.sv_onstack = 0;
- (void) sigvec (SIGCHLD,&chldvec,&oldvec);
- #endif
- nchildren = 0;
- for (;;) {
- x = service ();
- if (x != SCMOK) {
- logerr ("Error in establishing network connection");
- (void) servicekill ();
- continue;
- }
- #ifdef _ABI_SOURCE
- sigemptyset (&signalmask);
- sigaddset (&signalmask, SIGCHLD);
- (void) sigprocmask (SIG_BLOCK, &signalmask, &oldsignalmask);
- #else
- signalmask = sigblock(sigmask(SIGCHLD));
- #endif
- if ((pid = fork()) == 0) { /* server process */
- (void) serviceprep ();
- answer ();
- (void) serviceend ();
- exit (0);
- }
- (void) servicekill (); /* parent */
- if (pid > 0) nchildren++;
- #ifdef _ABI_SOURCE
- (void) sigprocmask (SIG_SETMASK, &oldsignalmask, NULL);
- #else
- (void) sigsetmask(signalmask);
- #endif
- }
- }
-
- /*
- * Child status signal handler
- */
-
- chldsig()
- {
- union wait w;
-
- /* XXX all the signal stuff needs attention */
- while (wait3(&w, WNOHANG, (struct rusage *)0) > 0) {
- if (nchildren) nchildren--;
- }
- }
-
- /*****************************************
- *** I N I T I A L I Z A T I O N ***
- *****************************************/
-
- usage ()
- {
- quit (1,"Usage: supfilesrv [ -l | -P | -N | -C <max children> | -H <host> <user> <cryptfile> <supargs> ]\n");
- }
-
- init (argc,argv)
- int argc;
- char **argv;
- {
- register int i;
- register int x;
- char *clienthost,*clientuser;
- char *p,*q;
- char buf[STRINGLENGTH];
- int maxsleep;
- register FILE *f;
-
- #ifdef RCS
- candorcs = FALSE;
- #endif
- live = FALSE;
- dbgportsq = FALSE;
- scmdebug = 0;
- clienthost = NULL;
- clientuser = NULL;
- maxsleep = 5;
- if (--argc < 0)
- usage ();
- argv++;
- while (clienthost == NULL && argc > 0 && argv[0][0] == '-') {
- switch (argv[0][1]) {
- case 'l':
- live = TRUE;
- break;
- case 'P':
- dbgportsq = TRUE;
- break;
- case 'N':
- scmdebug++;
- break;
- case 'C':
- if (--argc < 1)
- quit (1,"Missing arg to -C\n");
- argv++;
- maxchildren = atoi(argv[0]);
- break;
- case 'H':
- if (--argc < 3)
- quit (1,"Missing args to -H\n");
- argv++;
- clienthost = argv[0];
- clientuser = argv[1];
- cryptkey = argv[2];
- argc -= 2;
- argv += 2;
- break;
- #ifdef RCS
- case 'R':
- candorcs = TRUE;
- break;
- #endif
- default:
- fprintf (stderr,"Unknown flag %s ignored\n",argv[0]);
- break;
- }
- --argc;
- argv++;
- }
- if (clienthost == NULL) {
- if (argc != 0)
- usage ();
- x = servicesetup (dbgportsq ? DEBUGFPORT : FILEPORT);
- if (x != SCMOK)
- quit (1,"Error in network setup");
- for (i = 0; i < HASHSIZE; i++)
- uidH[i] = gidH[i] = inodeH[i] = NULL;
- return;
- }
- server = FALSE;
- if (argc < 1)
- usage ();
- f = fopen (cryptkey,"r");
- if (f == NULL)
- quit (1,"Unable to open cryptfile %s\n",cryptkey);
- if (p = fgets (buf,STRINGLENGTH,f)) {
- if (q = index (p,'\n')) *q = '\0';
- if (*p == '\0')
- quit (1,"No cryptkey found in %s\n",cryptkey);
- cryptkey = salloc (buf);
- }
- (void) fclose (f);
- x = request (dbgportsq ? DEBUGFPORT : FILEPORT,clienthost,&maxsleep);
- if (x != SCMOK)
- quit (1,"Unable to connect to host %s\n",clienthost);
- x = msgsignon ();
- if (x != SCMOK)
- quit (1,"Error sending signon request to fileserver\n");
- x = msgsignonack ();
- if (x != SCMOK)
- quit (1,"Error reading signon reply from fileserver\n");
- printf ("SUP Fileserver %d.%d (%s) %d on %s\n",
- protver,pgmver,scmver,fspid,remotehost());
- free (scmver);
- scmver = NULL;
- if (protver < 7)
- quit (1,"Remote fileserver does not implement reverse sup\n");
- xpatch = TRUE;
- xuser = clientuser;
- x = msgsetup ();
- if (x != SCMOK)
- quit (1,"Error sending setup request to fileserver\n");
- x = msgsetupack ();
- if (x != SCMOK)
- quit (1,"Error reading setup reply from fileserver\n");
- switch (setupack) {
- case FSETUPOK:
- break;
- case FSETUPSAME:
- quit (1,"User %s not found on remote client\n",xuser);
- case FSETUPHOST:
- quit (1,"This host has no permission to reverse sup\n");
- default:
- quit (1,"Unrecognized file server setup status %d\n",setupack);
- }
- if (netcrypt (cryptkey) != SCMOK )
- quit (1,"Running non-crypting fileserver\n");
- crypttest = CRYPTTEST;
- x = msgcrypt ();
- if (x != SCMOK)
- quit (1,"Error sending encryption test request\n");
- x = msgcryptok ();
- if (x == SCMEOF)
- quit (1,"Data encryption test failed\n");
- if (x != SCMOK)
- quit (1,"Error reading encryption test reply\n");
- logcrypt = CRYPTTEST;
- loguser = NULL;
- logpswd = NULL;
- if (netcrypt (PSWDCRYPT) != SCMOK) /* encrypt password data */
- quit (1,"Running non-crypting fileserver\n");
- x = msglogin ();
- (void) netcrypt ((char *)NULL); /* turn off encryption */
- if (x != SCMOK)
- quit (1,"Error sending login request to file server\n");
- x = msglogack ();
- if (x != SCMOK)
- quit (1,"Error reading login reply from file server\n");
- if (logack == FLOGNG)
- quit (1,"%s\nImproper login to %s account\n",logerror,xuser);
- xargc = argc;
- xargv = argv;
- x = msgxpatch ();
- if (x != SCMOK)
- quit (1,"Error sending crosspatch request\n");
- crosspatch ();
- exit (0);
- }
-
- /*****************************************
- *** A N S W E R R E Q U E S T ***
- *****************************************/
-
- answer ()
- {
- long starttime;
- register int x;
- #ifdef _ABI_SOURCE
- struct rlimit rl;
- #endif
-
- progpid = fspid = getpid ();
- collname = NULL;
- basedir = NULL;
- prefix = NULL;
- release = NULL;
- rcs_branch = NULL;
- #ifdef CVS
- cvs_root = NULL;
- #endif
- goawayreason = NULL;
- donereason = NULL;
- lockfd = -1;
- starttime = time ((long *)NULL);
- if (!setjmp (sjbuf)) {
- signon ();
- setup ();
- docrypt ();
- login ();
- if (xpatch) {
- int fd;
-
- x = msgxpatch ();
- if (x != SCMOK)
- exit (0);
- xargv[0] = "sup";
- xargv[1] = "-X";
- xargv[xargc] = (char *)NULL;
- (void) dup2 (netfile,0);
- (void) dup2 (netfile,1);
- (void) dup2 (netfile,2);
- #ifdef _ABI_SOURCE
- getrlimit (RLIMIT_NOFILE, &rl);
- fd = rl.rlim_max;
- #else
- fd = getdtablesize ();
- #endif
- while (--fd > 2)
- (void) close (fd);
- execvp (xargv[0],xargv);
- exit (0);
- }
- listfiles ();
- sendfiles ();
- }
- finishup (starttime);
- if (collname) free (collname);
- if (basedir) free (basedir);
- if (prefix) free (prefix);
- if (release) free (release);
- if (rcs_branch) free (rcs_branch);
- #ifdef CVS
- if (cvs_root) free (cvs_root);
- #endif
- if (goawayreason) {
- if (donereason == goawayreason)
- donereason = NULL;
- free (goawayreason);
- }
- if (donereason) free (donereason);
- if (lockfd >= 0) (void) close (lockfd);
- endpwent ();
- (void) endgrent ();
- #if CMUCS
- endacent ();
- #endif /* CMUCS */
- Hfree (uidH);
- Hfree (gidH);
- Hfree (inodeH);
- }
-
- /*****************************************
- *** S I G N O N C L I E N T ***
- *****************************************/
-
- signon ()
- {
- register int x;
-
- xpatch = FALSE;
- x = msgsignon ();
- if (x != SCMOK) goaway ("Error reading signon request from client");
- x = msgsignonack ();
- if (x != SCMOK) goaway ("Error sending signon reply to client");
- free (scmver);
- scmver = NULL;
- }
-
- /*****************************************************************
- *** E X C H A N G E S E T U P I N F O R M A T I O N ***
- *****************************************************************/
-
- setup ()
- {
- register int x;
- char *p,*q;
- char buf[STRINGLENGTH];
- register FILE *f;
- struct stat sbuf;
- register TREELIST *tl;
-
- if (protver > 7) {
- cancompress = TRUE;
- }
- x = msgsetup ();
- if (x != SCMOK) goaway ("Error reading setup request from client");
- if (protver < 4) {
- setupack = FSETUPOLD;
- (void) msgsetupack ();
- if (protver >= 6) longjmp (sjbuf,TRUE);
- goaway ("Sup client using obsolete version of protocol");
- }
- if (xpatch) {
- register struct passwd *pw;
- extern int link_nofollow(), local_file();
-
- if ((pw = getpwnam (xuser)) == NULL) {
- setupack = FSETUPSAME;
- (void) msgsetupack ();
- if (protver >= 6) longjmp (sjbuf,TRUE);
- goaway ("User not found");
- }
- (void) free (xuser);
- xuser = salloc (pw->pw_dir);
-
- /* check crosspatch host access file */
- cryptkey = NULL;
- (void) sprintf (buf,FILEXPATCH,xuser);
-
- /* Turn off link following */
- if (link_nofollow(1) != -1) {
- int hostok = FALSE;
- /* get stat info before open */
- if (stat(buf, &sbuf) == -1)
- (void) bzero((char *)&sbuf, sizeof(sbuf));
-
- if ((f = fopen (buf,"r")) != NULL) {
- struct stat fsbuf;
-
- while (p = fgets (buf,STRINGLENGTH,f)) {
- q = index (p,'\n');
- if (q) *q = 0;
- if (index ("#;:",*p)) continue;
- q = nxtarg (&p," \t");
- if (*p == '\0') continue;
- if (!matchhost(q)) continue;
-
- cryptkey = salloc (p);
- hostok = TRUE;
- if (local_file(fileno(f), &fsbuf) > 0
- && stat_info_ok(&sbuf, &fsbuf)) {
- runas_uid = sbuf.st_uid;
- runas_gid = sbuf.st_gid;
- }
- break;
- }
- (void) fclose (f);
- }
-
- /* Restore link following */
- if (link_nofollow(0) == -1)
- goaway ("Restore link following");
-
- if (!hostok) {
- setupack = FSETUPHOST;
- (void) msgsetupack ();
- if (protver >= 6) longjmp (sjbuf,TRUE);
- goaway ("Host not on access list");
- }
- }
- setupack = FSETUPOK;
- x = msgsetupack ();
- if (x != SCMOK)
- goaway ("Error sending setup reply to client");
- return;
- }
- #ifdef RCS
- if (candorcs && release != NULL &&
- (strncmp(release, "RCS.", 4) == 0)) {
- rcs_branch = salloc(&release[4]);
- free(release);
- release = salloc("RCS");
- dorcs = TRUE;
- }
- #endif
- if (release == NULL)
- release = salloc (DEFRELEASE);
- if (basedir == NULL || *basedir == '\0') {
- basedir = NULL;
- (void) sprintf (buf,FILEDIRS,DEFDIR);
- f = fopen (buf,"r");
- if (f) {
- while (p = fgets (buf,STRINGLENGTH,f)) {
- q = index (p,'\n');
- if (q) *q = 0;
- if (index ("#;:",*p)) continue;
- q = nxtarg (&p," \t=");
- if (strcmp(q,collname) == 0) {
- basedir = skipover(p," \t=");
- basedir = salloc (basedir);
- break;
- }
- }
- (void) fclose (f);
- }
- if (basedir == NULL) {
- (void) sprintf (buf,FILEBASEDEFAULT,collname);
- basedir = salloc(buf);
- }
- }
- if (chdir (basedir) < 0)
- goaway ("Can't chdir to base directory %s",basedir);
- (void) sprintf (buf,FILEPREFIX,collname);
- f = fopen (buf,"r");
- if (f) {
- while (p = fgets (buf,STRINGLENGTH,f)) {
- q = index (p,'\n');
- if (q) *q = 0;
- if (index ("#;:",*p)) continue;
- prefix = salloc(p);
- if (chdir (prefix) < 0)
- goaway ("Can't chdir to %s from base directory %s",
- prefix,basedir);
- break;
- }
- (void) fclose (f);
- }
- x = stat (".",&sbuf);
- if (prefix) (void) chdir (basedir);
- if (x < 0)
- goaway ("Can't stat base/prefix directory");
- if (nchildren >= maxchildren) {
- setupack = FSETUPBUSY;
- (void) msgsetupack ();
- if (protver >= 6) longjmp (sjbuf,TRUE);
- goaway ("Sup client told to try again later");
- }
- if (sbuf.st_dev == basedev && sbuf.st_ino == baseino && samehost()) {
- setupack = FSETUPSAME;
- (void) msgsetupack ();
- if (protver >= 6) longjmp (sjbuf,TRUE);
- goaway ("Attempt to upgrade to same directory on same host");
- }
- /* obtain release information */
- if (!getrelease (release)) {
- setupack = FSETUPRELEASE;
- (void) msgsetupack ();
- if (protver >= 6) longjmp (sjbuf,TRUE);
- goaway ("Invalid release information");
- }
- /* check host access file */
- cryptkey = NULL;
- for (tl = listTL; tl != NULL; tl = tl->TLnext) {
- char *h;
- if ((h = tl->TLhost) == NULL)
- h = FILEHOSTDEF;
- (void) sprintf (buf,FILEHOST,collname,h);
- f = fopen (buf,"r");
- if (f) {
- int hostok = FALSE;
- while (p = fgets (buf,STRINGLENGTH,f)) {
- int not;
- q = index (p,'\n');
- if (q) *q = 0;
- if (index ("#;:",*p)) continue;
- q = nxtarg (&p," \t");
- if ((not = (*q == '!')) && *++q == '\0')
- q = nxtarg (&p," \t");
- hostok = (not == (matchhost(q) == 0));
- if (hostok) {
- while ((*p == ' ') || (*p == '\t')) p++;
- if (*p) cryptkey = salloc (p);
- break;
- }
- }
- (void) fclose (f);
- if (!hostok) {
- setupack = FSETUPHOST;
- (void) msgsetupack ();
- if (protver >= 6) longjmp (sjbuf,TRUE);
- goaway ("Host not on access list for %s",
- collname);
- }
- }
- }
- /* try to lock collection */
- (void) sprintf (buf,FILELOCK,collname);
- x = open (buf,O_RDONLY,0);
- if (x >= 0) {
- if (flock (x,(LOCK_SH|LOCK_NB)) < 0) {
- (void) close (x);
- if (errno != EWOULDBLOCK)
- goaway ("Can't lock collection %s",collname);
- setupack = FSETUPBUSY;
- (void) msgsetupack ();
- if (protver >= 6) longjmp (sjbuf,TRUE);
- goaway ("Sup client told to wait for lock");
- }
- lockfd = x;
- }
- setupack = FSETUPOK;
- x = msgsetupack ();
- if (x != SCMOK) goaway ("Error sending setup reply to client");
- }
-
- /** Test data encryption **/
- docrypt ()
- {
- register int x;
- char *p,*q;
- char buf[STRINGLENGTH];
- register FILE *f;
- struct stat sbuf;
- extern int link_nofollow(), local_file();
-
- if (!xpatch) {
- (void) sprintf (buf,FILECRYPT,collname);
-
- /* Turn off link following */
- if (link_nofollow(1) != -1) {
- /* get stat info before open */
- if (stat(buf, &sbuf) == -1)
- (void) bzero((char *)&sbuf, sizeof(sbuf));
-
- if ((f = fopen (buf,"r")) != NULL) {
- struct stat fsbuf;
-
- if (cryptkey == NULL &&
- (p = fgets (buf,STRINGLENGTH,f))) {
- if (q = index (p,'\n')) *q = '\0';
- if (*p) cryptkey = salloc (buf);
- }
- if (local_file(fileno(f), &fsbuf) > 0
- && stat_info_ok(&sbuf, &fsbuf)) {
- runas_uid = sbuf.st_uid;
- runas_gid = sbuf.st_gid;
- }
- (void) fclose (f);
- }
- /* Restore link following */
- if (link_nofollow(0) == -1)
- goaway ("Restore link following");
- }
- }
- if ( netcrypt (cryptkey) != SCMOK )
- goaway ("Runing non-crypting supfilesrv");
- x = msgcrypt ();
- if (x != SCMOK)
- goaway ("Error reading encryption test request from client");
- (void) netcrypt ((char *)NULL);
- if (strcmp(crypttest,CRYPTTEST) != 0)
- goaway ("Client not encrypting data properly");
- free (crypttest);
- crypttest = NULL;
- x = msgcryptok ();
- if (x != SCMOK)
- goaway ("Error sending encryption test reply to client");
- }
-
- /***************************************************************
- *** C O N N E C T T O P R O P E R A C C O U N T ***
- ***************************************************************/
-
- login ()
- {
- char *changeuid ();
- register int x,fileuid,filegid;
-
- (void) netcrypt (PSWDCRYPT); /* encrypt acct name and password */
- x = msglogin ();
- (void) netcrypt ((char *)NULL); /* turn off encryption */
- if (x != SCMOK) goaway ("Error reading login request from client");
- if ( logcrypt ) {
- if (strcmp(logcrypt,CRYPTTEST) != 0) {
- logack = FLOGNG;
- logerror = "Improper login encryption";
- (void) msglogack ();
- goaway ("Client not encrypting login information properly");
- }
- free (logcrypt);
- logcrypt = NULL;
- }
- if (loguser == NULL) {
- if (cryptkey) {
- if (runas_uid >= 0 && runas_gid >= 0) {
- fileuid = runas_uid;
- filegid = runas_gid;
- loguser = NULL;
- } else
- loguser = salloc (DEFUSER);
- } else
- loguser = salloc (DEFUSER);
- }
- if ((logerror = changeuid (loguser,logpswd,fileuid,filegid)) != NULL) {
- logack = FLOGNG;
- (void) msglogack ();
- if (protver >= 6) longjmp (sjbuf,TRUE);
- goaway ("Client denied login access");
- }
- if (loguser) free (loguser);
- if (logpswd) free (logpswd);
- logack = FLOGOK;
- x = msglogack ();
- if (x != SCMOK) goaway ("Error sending login reply to client");
- if (!xpatch) /* restore desired encryption */
- if (netcrypt (cryptkey) != SCMOK)
- goaway("Running non-crypting supfilesrv");
- free (cryptkey);
- cryptkey = NULL;
- }
-
- /*****************************************
- *** M A K E N A M E L I S T ***
- *****************************************/
-
- listfiles ()
- {
- int denyone();
- register int x;
-
- refuseT = NULL;
- x = msgrefuse ();
- if (x != SCMOK) goaway ("Error reading refuse list from client");
- getscanlists ();
- Tfree (&refuseT);
- x = msglist ();
- if (x != SCMOK) goaway ("Error sending file list to client");
- Tfree (&listT);
- listT = NULL;
- needT = NULL;
- x = msgneed ();
- if (x != SCMOK)
- goaway ("Error reading needed files list from client");
- denyT = NULL;
- (void) Tprocess (needT,denyone);
- Tfree (&needT);
- x = msgdeny ();
- if (x != SCMOK) goaway ("Error sending denied files list to client");
- Tfree (&denyT);
- }
-
- denyone (t)
- register TREE *t;
- {
- register TREELIST *tl;
- register char *name = t->Tname;
- register int update = (t->Tflags&FUPDATE) != 0;
- struct stat sbuf;
- register TREE *tlink;
- TREE *linkcheck ();
- char slinkname[STRINGLENGTH];
- register int x;
-
- for (tl = listTL; tl != NULL; tl = tl->TLnext)
- if ((t = Tsearch (tl->TLtree,name)) != NULL)
- break;
- if (t == NULL) {
- (void) Tinsert (&denyT,name,FALSE);
- return (SCMOK);
- }
- cdprefix (tl->TLprefix);
- if ((t->Tmode&S_IFMT) == S_IFLNK)
- x = lstat(name,&sbuf);
- else
- x = stat(name,&sbuf);
- if (x < 0 || (sbuf.st_mode&S_IFMT) != (t->Tmode&S_IFMT)) {
- (void) Tinsert (&denyT,name,FALSE);
- return (SCMOK);
- }
- switch (t->Tmode&S_IFMT) {
- case S_IFLNK:
- if ((x = readlink (name,slinkname,STRINGLENGTH)) <= 0) {
- (void) Tinsert (&denyT,name,FALSE);
- return (SCMOK);
- }
- slinkname[x] = '\0';
- (void) Tinsert (&t->Tlink,slinkname,FALSE);
- break;
- case S_IFREG:
- if (sbuf.st_nlink > 1 &&
- (tlink = linkcheck (t,(int)sbuf.st_dev,(int)sbuf.st_ino)))
- {
- (void) Tinsert (&tlink->Tlink,name,FALSE);
- return (SCMOK);
- }
- if (update) t->Tflags |= FUPDATE;
- case S_IFDIR:
- t->Tuid = sbuf.st_uid;
- t->Tgid = sbuf.st_gid;
- break;
- default:
- (void) Tinsert (&denyT,name,FALSE);
- return (SCMOK);
- }
- t->Tflags |= FNEEDED;
- return (SCMOK);
- }
-
- /*********************************
- *** S E N D F I L E S ***
- *********************************/
-
- sendfiles ()
- {
- int sendone(),senddir(),sendfile();
- register TREELIST *tl;
- register int x;
-
- /* Does the protocol support compression */
- if (cancompress) {
- /* Check for compression on sending files */
- x = msgcompress();
- if ( x != SCMOK)
- goaway ("Error sending compression check to server");
- }
- /* send all files */
- for (tl = listTL; tl != NULL; tl = tl->TLnext) {
- cdprefix (tl->TLprefix);
- #ifdef CVS
- if (candorcs) {
- cvs_root = getcwd(NULL, 256);
- if (access("CVSROOT", F_OK) < 0)
- dorcs = FALSE;
- else {
- loginfo("is a CVSROOT \"%s\"\n", cvs_root);
- dorcs = TRUE;
- }
- }
- #endif
- (void) Tprocess (tl->TLtree,sendone);
- }
- /* send directories in reverse order */
- for (tl = listTL; tl != NULL; tl = tl->TLnext) {
- cdprefix (tl->TLprefix);
- (void) Trprocess (tl->TLtree,senddir);
- }
- x = msgsend ();
- if (x != SCMOK)
- goaway ("Error reading receive file request from client");
- upgradeT = NULL;
- x = msgrecv (sendfile,0);
- if (x != SCMOK)
- goaway ("Error sending file to client");
- }
-
- sendone (t)
- TREE *t;
- {
- register int x,fd;
- register int fdtmp;
- char sys_com[STRINGLENGTH], temp_file[STRINGLENGTH], rcs_file[STRINGLENGTH];
- union wait status;
- char *uconvert(),*gconvert();
- int sendfile ();
-
- if ((t->Tflags&FNEEDED) == 0) /* only send needed files */
- return (SCMOK);
- if ((t->Tmode&S_IFMT) == S_IFDIR) /* send no directories this pass */
- return (SCMOK);
- x = msgsend ();
- if (x != SCMOK) goaway ("Error reading receive file request from client");
- upgradeT = t; /* upgrade file pointer */
- fd = -1; /* no open file */
- if ((t->Tmode&S_IFMT) == S_IFREG) {
- if (!listonly && (t->Tflags&FUPDATE) == 0) {
- #ifdef RCS
- if (dorcs) {
- char rcs_release[STRINGLENGTH];
-
- tmpnam(rcs_file);
- if (strcmp(&t->Tname[strlen(t->Tname)-2], ",v") == 0) {
- t->Tname[strlen(t->Tname)-2] = '\0';
- if (rcs_branch != NULL)
- #ifdef CVS
- sprintf(rcs_release, "-r %s", rcs_branch);
- #else
- sprintf(rcs_release, "-r%s", rcs_branch);
- #endif
- else
- rcs_release[0] = '\0';
- #ifdef CVS
- sprintf(sys_com, "cvs -d %s -r -l -Q co -p %s %s > %s\n", cvs_root, rcs_release, t->Tname, rcs_file);
- #else
- sprintf(sys_com, "co -q -p %s %s > %s 2> /dev/null\n", rcs_release, t->Tname, rcs_file);
- #endif
- /*loginfo("using rcs mode \"%s\"\n", sys_com);*/
- status.w_status = system(sys_com);
- if (status.w_status < 0 || status.w_retcode) {
- /* Just in case */
- unlink(rcs_file);
- if (status.w_status < 0) {
- goaway ("We died trying to \"%s\"", sys_com);
- t->Tmode = 0;
- }
- else {
- /*logerr("rcs command failed \"%s\" = %d\n",
- sys_com, status.w_retcode);*/
- t->Tflags |= FUPDATE;
- }
- }
- else if (docompress) {
- tmpnam(temp_file);
- sprintf(sys_com, "gzip -c < %s > %s\n", rcs_file, temp_file);
- if (system(sys_com) < 0) {
- /* Just in case */
- unlink(temp_file);
- unlink(rcs_file);
- goaway ("We died trying to \"%s\"", sys_com);
- t->Tmode = 0;
- }
- fd = open (temp_file,O_RDONLY,0);
- }
- else
- fd = open (rcs_file,O_RDONLY,0);
- }
- }
- #endif
- if (fd == -1) {
- if (docompress) {
- tmpnam(temp_file);
- sprintf(sys_com, "gzip -c < %s > %s\n", t->Tname, temp_file);
- if (system(sys_com) < 0) {
- /* Just in case */
- unlink(temp_file);
- goaway ("We died trying to \"%s\"", sys_com);
- t->Tmode = 0;
- }
- fd = open (temp_file,O_RDONLY,0);
- }
- else
- fd = open (t->Tname,O_RDONLY,0);
- }
- if (fd < 0 && (t->Tflags&FUPDATE) == 0) t->Tmode = 0;
- }
- if (t->Tmode) {
- t->Tuser = salloc (uconvert (t->Tuid));
- t->Tgroup = salloc (gconvert (t->Tgid));
- }
- }
- x = msgrecv (sendfile,fd);
- if (docompress)
- unlink(temp_file);
- #ifdef RCS
- if (dorcs)
- unlink(rcs_file);
- #endif
- if (x != SCMOK) goaway ("Error sending file to client");
- return (SCMOK);
- }
-
- senddir (t)
- TREE *t;
- {
- register int x;
- char *uconvert(),*gconvert();
- int sendfile ();
-
- if ((t->Tflags&FNEEDED) == 0) /* only send needed files */
- return (SCMOK);
- if ((t->Tmode&S_IFMT) != S_IFDIR) /* send only directories this pass */
- return (SCMOK);
- x = msgsend ();
- if (x != SCMOK) goaway ("Error reading receive file request from client");
- upgradeT = t; /* upgrade file pointer */
- t->Tuser = salloc (uconvert (t->Tuid));
- t->Tgroup = salloc (gconvert (t->Tgid));
- x = msgrecv (sendfile,0);
- if (x != SCMOK) goaway ("Error sending file to client");
- return (SCMOK);
- }
-
- sendfile (t,ap)
- register TREE *t;
- va_list ap;
- {
- register int x;
- int fd = va_arg(ap,int);
- if ((t->Tmode&S_IFMT) != S_IFREG || listonly || (t->Tflags&FUPDATE))
- return (SCMOK);
- x = writefile (fd);
- if (x != SCMOK) goaway ("Error sending file to client");
- (void) close (fd);
- return (SCMOK);
- }
-
- /*****************************************
- *** E N D C O N N E C T I O N ***
- *****************************************/
-
- finishup (starttime)
- long starttime;
- {
- register int x = SCMOK;
- char tmpbuf[BUFSIZ], *p, lognam[STRINGLENGTH];
- int logfd;
- struct stat sbuf;
- long finishtime;
- char *releasename;
-
- (void) netcrypt ((char *)NULL);
- if (protver < 6) {
- if (goawayreason != NULL)
- free (goawayreason);
- goawayreason = (char *)NULL;
- x = msggoaway();
- doneack = FDONESUCCESS;
- donereason = salloc ("Unknown");
- } else if (goawayreason == (char *)NULL)
- x = msgdone ();
- else {
- doneack = FDONEGOAWAY;
- donereason = goawayreason;
- }
- if (x == SCMEOF || x == SCMERR) {
- doneack = FDONEUSRERROR;
- donereason = salloc ("Premature EOF on network");
- } else if (x != SCMOK) {
- doneack = FDONESRVERROR;
- donereason = salloc ("Unknown SCM code");
- }
- if (doneack == FDONEDONTLOG)
- return;
- if (donereason == NULL)
- donereason = salloc ("No reason");
- if (doneack == FDONESRVERROR || doneack == FDONEUSRERROR)
- logerr ("%s", donereason);
- else if (doneack == FDONEGOAWAY)
- logerr ("GOAWAY: %s",donereason);
- else if (doneack != FDONESUCCESS)
- logerr ("Reason %d: %s",doneack,donereason);
- goawayreason = donereason;
- cdprefix ((char *)NULL);
- (void) sprintf (lognam,FILELOGFILE,collname);
- if ((logfd = open(lognam,O_APPEND|O_WRONLY,0644)) < 0)
- return; /* can not open file up...error */
- finishtime = time ((long *)NULL);
- p = tmpbuf;
- (void) sprintf (p,"%s ",fmttime (lasttime));
- p += strlen(p);
- (void) sprintf (p,"%s ",fmttime (starttime));
- p += strlen(p);
- (void) sprintf (p,"%s ",fmttime (finishtime));
- p += strlen(p);
- if ((releasename = release) == NULL)
- releasename = "UNKNOWN";
- (void) sprintf (p,"%s %s %d %s\n",remotehost(),releasename,
- FDONESUCCESS-doneack,donereason);
- p += strlen(p);
- #if MACH
- /* if we are busy dont get stuck updating the disk if full */
- if(setupack == FSETUPBUSY) {
- long l = FIOCNOSPC_ERROR;
- ioctl(logfd, FIOCNOSPC, &l);
- }
- #endif /* MACH */
- (void) write(logfd,tmpbuf,(p - tmpbuf));
- (void) close(logfd);
- }
-
- /***************************************************
- *** H A S H T A B L E R O U T I N E S ***
- ***************************************************/
-
- Hfree (table)
- HASH **table;
- {
- register HASH *h;
- register int i;
- for (i = 0; i < HASHSIZE; i++)
- while (h = table[i]) {
- table[i] = h->Hnext;
- if (h->Hname) free (h->Hname);
- free ((char *)h);
- }
- }
-
- HASH *Hlookup (table,num1,num2)
- HASH **table;
- int num1,num2;
- {
- register HASH *h;
- register int hno;
- hno = HASHFUNC(num1,num2);
- for (h = table[hno]; h && (h->Hnum1 != num1 || h->Hnum2 != num2); h = h->Hnext);
- return (h);
- }
-
- Hinsert (table,num1,num2,name,tree)
- HASH **table;
- int num1,num2;
- char *name;
- TREE *tree;
- {
- register HASH *h;
- register int hno;
- hno = HASHFUNC(num1,num2);
- h = (HASH *) malloc (sizeof(HASH));
- h->Hnum1 = num1;
- h->Hnum2 = num2;
- h->Hname = name;
- h->Htree = tree;
- h->Hnext = table[hno];
- table[hno] = h;
- }
-
- /*********************************************
- *** U T I L I T Y R O U T I N E S ***
- *********************************************/
-
- TREE *linkcheck (t,d,i)
- TREE *t;
- int d,i; /* inode # and device # */
- {
- register HASH *h;
- h = Hlookup (inodeH,i,d);
- if (h) return (h->Htree);
- Hinsert (inodeH,i,d,(char *)NULL,t);
- return ((TREE *)NULL);
- }
-
- char *uconvert (uid)
- int uid;
- {
- register struct passwd *pw;
- register char *p;
- register HASH *u;
- u = Hlookup (uidH,uid,0);
- if (u) return (u->Hname);
- pw = getpwuid (uid);
- if (pw == NULL) return ("");
- p = salloc (pw->pw_name);
- Hinsert (uidH,uid,0,p,(TREE*)NULL);
- return (p);
- }
-
- char *gconvert (gid)
- int gid;
- {
- register struct group *gr;
- register char *p;
- register HASH *g;
- g = Hlookup (gidH,gid,0);
- if (g) return (g->Hname);
- gr = getgrgid (gid);
- if (gr == NULL) return ("");
- p = salloc (gr->gr_name);
- Hinsert (gidH,gid,0,p,(TREE *)NULL);
- return (p);
- }
-
- char *changeuid (namep,passwordp,fileuid,filegid)
- char *namep,*passwordp;
- int fileuid,filegid;
- {
- char *okpassword ();
- char *group,*account,*pswdp;
- struct passwd *pwd;
- struct group *grp;
- #if CMUCS
- struct account *acc;
- struct ttyloc tlc;
- #endif /* CMUCS */
- register int status = ACCESS_CODE_OK;
- char nbuf[STRINGLENGTH];
- static char errbuf[STRINGLENGTH];
- #if CMUCS
- int *grps;
- #endif /* CMUCS */
- char *p;
-
- if (namep == NULL) {
- pwd = getpwuid (fileuid);
- if (pwd == NULL) {
- (void) sprintf (errbuf,"Reason: Unknown user id %d",
- fileuid);
- return (errbuf);
- }
- grp = getgrgid (filegid);
- if (grp) group = strcpy (nbuf,grp->gr_name);
- else group = NULL;
- account = NULL;
- pswdp = NULL;
- } else {
- (void) strcpy (nbuf,namep);
- account = group = index (nbuf,',');
- if (group != NULL) {
- *group++ = '\0';
- account = index (group,',');
- if (account != NULL) {
- *account++ = '\0';
- if (*account == '\0') account = NULL;
- }
- if (*group == '\0') group = NULL;
- }
- pwd = getpwnam (nbuf);
- if (pwd == NULL) {
- (void) sprintf (errbuf,"Reason: Unknown user %s",
- nbuf);
- return (errbuf);
- }
- if (strcmp (nbuf,DEFUSER) == 0)
- pswdp = NULL;
- else
- pswdp = passwordp ? passwordp : "";
- #ifdef AFS
- if (strcmp (nbuf,DEFUSER) != 0) {
- char *reason;
- setpag(); /* set a pag */
- if (ka_UserAuthenticate(pwd->pw_name, "", 0,
- pswdp, 1, &reason)) {
- (void) sprintf (errbuf,"AFS authentication failed, %s",
- reason);
- logerr ("Attempt by %s; %s",
- nbuf, errbuf);
- return (errbuf);
- }
- }
- #endif
- }
- if (getuid () != 0) {
- if (getuid () == pwd->pw_uid)
- return (NULL);
- if (strcmp (pwd->pw_name,DEFUSER) == 0)
- return (NULL);
- logerr ("Fileserver not superuser");
- return ("Reason: fileserver is not running privileged");
- }
- #if CMUCS
- tlc.tlc_hostid = TLC_UNKHOST;
- tlc.tlc_ttyid = TLC_UNKTTY;
- if (okaccess(pwd->pw_name,ACCESS_TYPE_SU,0,-1,tlc) != 1)
- status = ACCESS_CODE_DENIED;
- else {
- grp = NULL;
- acc = NULL;
- status = oklogin(pwd->pw_name,group,&account,pswdp,&pwd,&grp,&acc,&grps);
- if (status == ACCESS_CODE_OK) {
- if ((p = okpassword(pswdp,pwd->pw_name,pwd->pw_gecos)) != NULL)
- status = ACCESS_CODE_INSECUREPWD;
- }
- }
- #else /* CMUCS */
- status = ACCESS_CODE_OK;
- if (namep && strcmp(pwd->pw_name, DEFUSER) != 0)
- if (strcmp(pwd->pw_passwd,(char *)crypt(pswdp,pwd->pw_passwd)))
- status = ACCESS_CODE_BADPASSWORD;
- #endif /* CMUCS */
- switch (status) {
- case ACCESS_CODE_OK:
- break;
- case ACCESS_CODE_BADPASSWORD:
- p = "Reason: Invalid password";
- break;
- #if CMUCS
- case ACCESS_CODE_INSECUREPWD:
- (void) sprintf (errbuf,"Reason: %s",p);
- p = errbuf;
- break;
- case ACCESS_CODE_DENIED:
- p = "Reason: Access denied";
- break;
- case ACCESS_CODE_NOUSER:
- p = errbuf;
- break;
- case ACCESS_CODE_ACCEXPIRED:
- p = "Reason: Account expired";
- break;
- case ACCESS_CODE_GRPEXPIRED:
- p = "Reason: Group expired";
- break;
- case ACCESS_CODE_ACCNOTVALID:
- p = "Reason: Invalid account";
- break;
- case ACCESS_CODE_MANYDEFACC:
- p = "Reason: User has more than one default account";
- break;
- case ACCESS_CODE_NOACCFORGRP:
- p = "Reason: No account for group";
- break;
- case ACCESS_CODE_NOGRPFORACC:
- p = "Reason: No group for account";
- break;
- case ACCESS_CODE_NOGRPDEFACC:
- p = "Reason: No group for default account";
- break;
- case ACCESS_CODE_NOTGRPMEMB:
- p = "Reason: Not member of group";
- break;
- case ACCESS_CODE_NOTDEFMEMB:
- p = "Reason: Not member of default group";
- break;
- case ACCESS_CODE_OOPS:
- p = "Reason: Internal error";
- break;
- #endif /* CMUCS */
- default:
- (void) sprintf (p = errbuf,"Reason: Status %d",status);
- break;
- }
- if (pwd == NULL)
- return (p);
- if (status != ACCESS_CODE_OK) {
- logerr ("Login failure for %s",pwd->pw_name);
- logerr ("%s",p);
- #if CMUCS
- logaccess (pwd->pw_name,ACCESS_TYPE_SUP,status,0,-1,tlc);
- #endif /* CMUCS */
- return (p);
- }
- #if CMUCS
- if (setgroups (grps[0], &grps[1]) < 0)
- logerr ("setgroups: %%m");
- if (setgid ((gid_t)grp->gr_gid) < 0)
- logerr ("setgid: %%m");
- if (setuid ((uid_t)pwd->pw_uid) < 0)
- logerr ("setuid: %%m");
- #else /* CMUCS */
- if (initgroups (pwd->pw_name,pwd->pw_gid) < 0)
- return("Error setting group list");
- if (setgid (pwd->pw_gid) < 0)
- logerr ("setgid: %%m");
- if (setuid (pwd->pw_uid) < 0)
- logerr ("setuid: %%m");
- #endif /* CMUCS */
- return (NULL);
- }
-
- #if __STDC__
- void
- goaway (char *fmt,...)
- #else
- /*VARARGS*//*ARGSUSED*/
- goaway (va_alist)
- va_dcl
- #endif
- {
- #if !__STDC__
- register char *fmt;
- #endif
- char buf[STRINGLENGTH];
- va_list ap;
-
- (void) netcrypt ((char *)NULL);
- #if __STDC__
- va_start(ap,fmt);
- #else
- va_start(ap);
- fmt = va_arg(ap,char *);
- #endif
- vsnprintf(buf, sizeof(buf), fmt, ap);
- va_end(ap);
- goawayreason = salloc (buf);
- (void) msggoaway ();
- logerr ("%s",buf);
- longjmp (sjbuf,TRUE);
- }
-
- char *fmttime (time)
- long time;
- {
- static char buf[STRINGLENGTH];
- int len;
-
- (void) strcpy (buf,ctime (&time));
- len = strlen(buf+4)-6;
- (void) strncpy (buf,buf+4,len);
- buf[len] = '\0';
- return (buf);
- }
-
- /*
- * Determine whether the file referenced by the file descriptor 'handle' can
- * be trusted, namely is it a file resident in the local file system.
- *
- * The main method of operation is to perform operations on the file
- * descriptor so that an attempt to spoof the checks should fail, for
- * example renamimg the file from underneath us and/or changing where the
- * file lives from underneath us.
- *
- * returns: -1 for error, indicating that we can not tell
- * 0 for file is definately not local, or it is an RFS link
- * 1 for file is local and can be trusted
- *
- * Side effect: copies the stat information into the supplied buffer,
- * regardless of the type of file system the file resides.
- *
- * Currently, the cases that we try to distinguish are RFS, AFS, NFS and
- * UFS, where the latter is considered a trusted file. We assume that the
- * caller has disabled link following and will detect an attempt to access
- * a file through an RFS link, except in the case the the last component is
- * an RFS link. With link following disabled, the last component itself is
- * interpreted as a regular file if it is really an RFS link, so we
- * disallow the RFS link identified by group "symlink" and mode "IEXEC by
- * owner only". An AFS file is
- * detected by trying the VIOCIGETCELL ioctl, which is one of the few AFS
- * ioctls which operate on a file descriptor. Note, this AFS ioctl is
- * implemented in the cache manager, so the decision does not involve a
- * query with the AFS file server. An NFS file is detected by looking at
- * the major device number and seeing if it matches the known values for
- * MACH NSF/Sun OS 3.x or Sun OS 4.x.
- *
- * Having the fstatfs() system call would make this routine easier and
- * more reliable.
- *
- * Note, in order to make the checks simpler, the file referenced by the
- * file descriptor can not be a BSD style symlink. Even with symlink
- * following of the last path component disabled, the attempt to open a
- * file which is a symlink will succeed, so we check for the BSD symlink
- * file type here. Also, the link following on/off and RFS file types
- * are only relevant in a MACH environment.
- */
- #ifdef AFS
- #include <sys/viceioctl.h>
- #endif
-
- #define SYMLINK_GRP 64
-
- int local_file(handle, sinfo)
- int handle;
- struct stat *sinfo;
- {
- struct stat sb;
- #ifdef VIOCIGETCELL
- /*
- * dummies for the AFS ioctl
- */
- struct ViceIoctl vdata;
- char cellname[512];
- #endif /* VIOCIGETCELL */
-
- if (fstat(handle, &sb) < 0)
- return(-1);
- if (sinfo != NULL)
- *sinfo = sb;
-
- #if CMUCS
- /*
- * If the following test succeeds, then the file referenced by
- * 'handle' is actually an RFS link, so we will not trust it.
- * See <sys/inode.h>.
- */
- if (sb.st_gid == SYMLINK_GRP
- && (sb.st_mode & (S_IFMT|S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)))
- == (S_IFREG|S_IEXEC))
- return(0);
- #endif /* CMUCS */
-
- /*
- * Do not trust BSD style symlinks either.
- */
- if ((sb.st_mode & S_IFMT) == S_IFLNK)
- return(0);
-
- #ifdef VIOCIGETCELL
- /*
- * This is the VIOCIGETCELL ioctl, which takes an fd, not
- * a path name. If it succeeds, then the file is in AFS.
- *
- * On failure, ENOTTY indicates that the file was not in
- * AFS; all other errors are pessimistically assumed to be
- * a temporary AFS error.
- */
- vdata.in_size = 0;
- vdata.out_size = sizeof(cellname);
- vdata.out = cellname;
- if (ioctl(handle, VIOCIGETCELL, (char *)&vdata) != -1)
- return(0);
- if (errno != ENOTTY)
- return(-1);
- #endif /* VIOCIGETCELL */
-
- /*
- * Verify the file is not in NFS.
- *
- * Our current implementation and Sun OS 3.x use major device
- * 255 for NFS files; Sun OS 4.x seems to use 130 (I have only
- * determined this empirically -- DLC). Without a fstatfs()
- * system call, this will have to do for now.
- */
- if (major(sb.st_dev) == 255 || major(sb.st_dev) == 130)
- return(0);
-
- return(1);
- }
-
- /*
- * Companion routine for ensuring that a local file can be trusted. Compare
- * various pieces of the stat information to make sure that the file can be
- * trusted. Returns true for stat information which meets the criteria
- * for being trustworthy. The main paranoia is to prevent a hard link to
- * a root owned file. Since the link could be removed after the file is
- * opened, a simply fstat() can not be relied upon. The two stat buffers
- * for comparison should come from a stat() on the file name and a following
- * fstat() on the open file. Some of the following checks are also an
- * additional level of paranoia. Also, this test will fail (correctly) if
- * either or both of the stat structures have all fields zeroed; typically
- * due to a stat() failure.
- */
-
-
- int stat_info_ok(sb1, sb2)
- struct stat *sb1, *sb2;
- {
- return (sb1->st_ino == sb2->st_ino && /* Still the same file */
- sb1->st_dev == sb2->st_dev && /* On the same device */
- sb1->st_mode == sb2->st_mode && /* Perms (and type) same */
- (sb1->st_mode & S_IFMT) == S_IFREG && /* Only allow reg files */
- (sb1->st_mode & 077) == 0 && /* Owner only perms */
- sb1->st_nlink == sb2->st_nlink && /* # hard links same... */
- sb1->st_nlink == 1 && /* and only 1 */
- sb1->st_uid == sb2->st_uid && /* owner and ... */
- sb1->st_gid == sb2->st_gid && /* group unchanged */
- sb1->st_mtime == sb2->st_mtime && /* Unmodified between stats */
- sb1->st_ctime == sb2->st_ctime); /* Inode unchanged. Hopefully
- a catch-all paranoid test */
- }
-
- #if MACH
- /*
- * Twiddle symbolic/RFS link following on/off. This is a no-op in a non
- * CMUCS/MACH environment. Also, the setmodes/getmodes interface is used
- * mainly because it is simpler than using table(2) directly.
- */
- #include <sys/table.h>
-
- int link_nofollow(on)
- int on;
- {
- static int modes = -1;
-
- if (modes == -1 && (modes = getmodes()) == -1)
- return(-1);
- if (on)
- return(setmodes(modes | UMODE_NOFOLLOW));
- return(setmodes(modes));
- }
- #else /* MACH */
- /*ARGSUSED*/
- int link_nofollow(on)
- int on;
- {
- return(0);
- }
- #endif /* MACH */
-